/*
The MIT License (MIT)

Copyright (c) 2013 Mike Dapiran, Brian May, Richard Pospesel, and Bert Wierenga

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software 
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#pragma once

#include "hhdVector2.h"
#include "hhdMatrix4.h"

#ifndef _EPSILON
#define _EPSILON 0.0000001f
#endif


namespace hhd
{
	class GUIPanel;

	/**
	* Transform2D is a 2D representation of the Transform data structure. This data structure stores
	* translation, rotation, and scale, much like Transform, except that rotation is simplified and
	* z component is removed from translation and scale. Methods are available to get this information
	* as well as set it.
	*
	* Primarily, this data structure will be used in conjunction with GUIPanel objects. GUIPanels store
	* a Transform2D object, which represents where the object is in screen space.
	*
	* @see Transform
	* @see GUIPanel
	* @see Vector2
	* @see Matrix4
	*
	* @author Bert Wierenga
	* @author Ben Dapkiewicz
	*/
	class Transform2D
	{
	public:
		/**
		* Default Constructor; Creates a new Matrix4 for World, sets translation and rotation
		* to zero, and sets scale to one.
		*/
		Transform2D(void);

		/**
		* Destructor; Only responsibility is to delete the world matrix.
		*/
		~Transform2D(void);

		/**
		* Constructor; Creates a new Matrix4 for World, sets translation and rotation
		* to zero, and sets scale to one. Takes a GUIPanel to be it's owner.
		*/
		Transform2D(GUIPanel* in_owner);

		/*
		* Copy constructor; Copies translation, rotation, and scale.
		*/
		Transform2D(const Transform2D& in_other);

		/**
		* assignment operator; Copies the data in the other Transform2D.
		*
		* @param in_other The Transform2D to copy from.
		*/
		Transform2D& operator=(const Transform2D& in_other);


		/**
		* initialize method; Used at initialization time to make sure this transform is set up correctly.
		*/
		void initialize(GUIPanel* in_panel);


		/**
		* setTranslation method; Sets the translation.
		* 
		* @param p_x The x value of the new translation.
		* @param p_y The y value of the new translation.
		*/
		void setTranslation(float p_x, float p_y);

		/**
		* getTranslation method; Returns the local translation.
		*/
		Vector2 getTranslation();

		/**
		* getTranslation method; Returns the world translation.
		*/
		Vector2 getWorldTranslation();

		/**
		* setXBase method; Sets the x base value.
		*
		* @param p_x_base_x The base x value.
		* @param p_x_base_y The base y value.
		*/
		void setXBase(float p_x_base_x, float p_x_base_y);

		/**
		* setYBase method; Sets the y base value.
		*
		* @param p_y_base_x The base x value.
		* @param p_y_base_y The base y value.
		*/
		void setYBase(float p_y_base_x, float p_y_base_y);

		/**
		* setOrientation method; Sets the angle of orientation.
		*
		* @param p_angle The angle to set.
		*/
		void setOrientation(float p_angle);

		/**
		* getXBase method; Returns the base x.
		*/
		Vector2 getXBase();

		/**
		* getYBase method; Returns the base y.
		*/
		Vector2 getYBase();

		/**
		* getOrientation method; Returns the orientation.
		*/
		float getOrientation();

		/**
		* getWorldOrientation method; Returns the world orientation.
		*/
		float getWorldOrientation();

		/**
		* setScale method; Sets the scale.
		*
		* @param p_x The x value for the scale.
		* @param p_y The y value for the scale.
		*/
		void setScale(float p_x, float p_y);

		/**
		* getScale method; Returns the scale.
		*/
		Vector2 getScale();


		/**
		* translate method; Translates.
		*
		* @param p_x The x value to translate.
		* @param p_y the y value to translate.
		*/
		void translate(float p_x, float p_y);

		/**
		* rotate method; Rotates.
		*
		* @param p_angle The angle to rotate.
		*/
		void rotate(float p_angle);

		/**
		* scale method; Scales.
		*
		* @param p_x The x value to scale.
		* @param p_y the y value to scale.
		*/
		void scale(float p_x, float p_y);

		/**
		* getWorldMatrix method; returns, and possibly calculates, the internally stored Matrix4 of this
		* affine transform in world space. This operation is not cheap but internally it is kept track if
		* it is needs to be calculated or if the currently stored Matrix4 is correct.
		*
		* @return Returns a constant Matrix4 reference to the internally stored world matrix.
		*/
		const Matrix4& getWorldMatrix();

	private:
		friend class GUIPanel;

		/**
		* copy method; This will copy information from another Transform2D into this Transform2D.
		*
		* @param in_other The Transform2D to be copied from.
		*/
		Transform2D& copy(const Transform2D& in_other, GUIPanel* in_to_be_owner = NULL);

		//GUIPanel that owns this
		GUIPanel* _owner;

		//translation, rotation, and scale
		float m_translation_x, m_translation_y;
		Vector2 m_x_base;
		float m_scale_x, m_scale_y;

		//the world matrix
		Matrix4* m_world_matrix;
	};
}